import {Rule} from "async-validator/dist-types/interface.js";
import ArkTipType from "../../common-type/ark-tip-type";
import ArkInteractionType from "../../common-type/ark-interaction-type";

export interface Option {
  /**
   * 显示文本
   * easy-ui tree组件文本显示固定为属性text，为与其兼容只能选择text属性
   * */
  text: string;
  /** 选中值 */
  value: any;
  /** 如果具有children，则说明是树形结构 */
  children?: Option[];

  /**
   * 树形结构用到的其他字段有
   *  - iconCls：图标类名
   *  - state：tree-file类名
   */
  [propName: string]: any;
}

/** 布局模式 */
export const enum LayoutMode {
  /**
   * 行内布局
   *
   * 多行时不一定每项对齐
   * */
  INLINE = "inline",
  /**  网格布局 */
  GRID = "grid",
}

/** 表单布局 */
interface Layout {
  /** 布局模式 */
  mode?: LayoutMode;
  /** 表单项水平距离，以数字度量，等价于TailwindCSS gap-x-{gapX} */
  gapX?: number;
  /** 表单项垂直距离，以数字度量，等价于TailwindCSS gap-x-{gapY} */
  gapY?: number;

  /**
   * 表单列数
   *
   * 当布局为网格布局时有效
   * */
  column?: number;
  /**
   * 以字符串形式可视化定义表单布局
   *
   * 当布局为网格布局时有效，优先级高于column属性
   *
   * 语法参考：https://developer.mozilla.org/zh-CN/docs/Web/CSS/grid-template-areas，区域名称为 formItems 中 prop 属性
   * */
  visionTemplate?: string;
}

/** 表单项提示 */
interface Tip {
  /** 标题 */
  title?: string;
  /** 内容 */
  content: string;
  /** 类型 */
  type?: ArkTipType;

  /** 表单项提示组件v-bind指令参数 */
  attributes?: Record<string, any>;
  /** 表单项提示组件v-on指令参数 */
  events?: Record<string, any>;
}

/** 表单项的交互形式 */
export interface Interaction {
  /** 交互类型 */
  type?: ArkInteractionType;

  /**
   * 宽度
   * - 字符串类型，直接作为CSS width属性值
   * - 数字类型，单位为px
   *
   * 无默认值
   * */
  width?: string | number;

  // #### 文本域控件 ####
  /**
   * 文本控件的可见宽度，以平均字符宽度为单位
   *
   * 当交互类型为文本域时可用
   * */
  // cols?: number;
  /**
   * 文本控件的可见文本行数，其值必须为正整数。
   *
   * 当交互类型为文本域时可用
   * */
  rows?: number;

  // #### 选项控件 ####
  /**
   * 可选项。当交互类型需要选项时可用（例如下拉选择、复选框、单选框等）
   *
   * 可选项动态变化或异步获取时，可以定义为一个函数，如果异步获取可以返回一个Promise
   * */
  options?:
      | Option[]
      | ((formItem: FormItem) => Option[] | Promise<Option[]>);

  /**
   * 手动抓取选项。当交互类型需要选项（例如下拉选择、复选框、单选框）且 options 属性是函数时可用
   * - 值为false，组件在初始化时会调用 options
   * - 值为true，组件在初始化时不会调用 options。需手动调用 fetchOptions 方法抓取数据
   * */
  manualFetchOptions?: boolean;

  /**
   * 为异步选项数据添加额外的全部选项。当交互类型需要选项（例如下拉选择、复选框、单选框）且 options 属性是函数，返回值是Promise时可用
   * */
  extraAllOptionForAsync?: boolean | Option;

  // #### 时间类型控件 ####
  /**
   * 值格式字符串。当交互类型为时间类型时可用
   *
   * 参考：https://day.js.org/docs/zh-CN/parse/string-format
   *
   * 如未设定（默认），则表单值为一个 JavaScript Date对象。
   * */
  valueFormat?: string;

  /**
   * 显示格式字符串。当交互类型为时间类型时可用
   *
   * 参考：https://day.js.org/docs/zh-CN/parse/string-format
   * */
  showFormat?: string;

  // #### 数字类型控件 ####
  /**
   * 最小值。当交互类型为数字类型时可用
   * */
  min?: number;
  /**
   * 最大值。当交互类型为数字类型时可用
   * */
  max?: number;

  /**
   * 小数分隔符后最大精度。当交互类型为数字类型时可用
   * */
  precision?: number;

  /**
   * 点击增减按钮的增减量。当交互类型为数字类型时可用
   * */
  step?: number;

  // #### 只读文本 ####
  /**
   * 值转换
   * - 参数为表单项的值
   * - 返回值被用于页面显示
   *
   * 当交互类型为只读文本时可用。
   * */
  transform?: (val: any) => string;

  // #### 树形控件 ####
  /**
   * 节点展开事件。当交互类型为下拉树类型时可用
   * */
  onNodeExpand?: (node: any) => void;

  /**
   * 内嵌树v-bind指令参数。当交互类型为下拉树类型时可用
   * */
  treeAttributes?: Record<string, any>;
  /**
   * 内嵌树v-on指令参数。当交互类型为下拉树类型时可用
   * */
  treeEvents?: Record<string, any>;

  /** 表单项交互组件v-bind指令参数 */
  attributes?: Record<string, any>;
  /** 表单项交互组件v-on指令参数 */
  events?: Record<string, any>;
}

/** 表单项 */
export interface FormItem {
  /**
   * 表单项名称
   *
   * 名称动态变化时，可以定义为一个函数
   * */
  label?: string | ((model: Readonly<Record<string, any>>) => string);
  /** 表单项属性 */
  prop: string;
  /** 表单项属性值 */
  value?: any;
  /** 表单项提示 */
  tip?: string | Tip;

  /**
   * 表单项是否显示
   *
   * 当值为一个函数时，参数为 model 对象
   * */
  show?: boolean | ((params: { [propName: string]: any }) => boolean);
  /**
   * 表单项是否禁用
   *
   * 当值为一个函数时，参数为 model 对象
   * */
  disabled?: boolean | ((params: { [propName: string]: any }) => boolean);

  /**
   * 表单项占据列数
   *
   * 当布局为网格布局时有效
   * */
  span?: number;

  /**
   * 验证规则
   * - 单条规则可以是对象
   * - 多条规则可以是列表
   *
   * 参考：https://github.com/yiminghe/async-validator
   *
   * 当值为一个函数时，参数为 model 对象
   * */
  rule?: Rule | ((params: { [propName: string]: any }) => Rule);

  /** 表单项的交互形式 */
  interaction?: Interaction;

  /** 表单项组件v-bind指令参数 */
  attributes?: Record<string, any>;
  /** 表单项组件v-on指令参数 */
  events?: Record<string, any>;
}

export interface ArkFormOptions {
  /** 表单布局 */
  layout?: Layout;

  /** 表单项名称与交互控件之间的分隔符 */
  delimiter?: string;

  /** formItems 中 prop 属性作为key，value属性作为值的对象 */
  model?: Record<string, any>;

  /** 表单项 */
  formItems?: FormItem[];

  /** 表单项回车事件 */
  onFormItemEnter?: (formItem: FormItem) => void;

  /** 表单组件v-bind指令参数 */
  attributes?: Record<string, any>;
  /** 表单组件v-on指令参数 */
  events?: Record<string, any>;
}

/** options默认值 */
const arkFormOptionsDefault: Partial<ArkFormOptions> = {
  layout: {
    mode: LayoutMode.GRID,
    column: 2,
    gapX: 3,
    gapY: 4,
  },
  formItems: [],
  model: {},
  delimiter: "：",
  attributes: {
    "label-position": "right",
    "label-width": "auto",
    "require-asterisk-position": "left",
  },
};
export default arkFormOptionsDefault

/** 组件接口 */
export interface ArkFormInteractionExpose {
  /**
   * 触发可选项重新获取，当交互类型需要选项时可用（例如下拉选择、复选框、单选框）
   *
   * 适用于主动触发选项获取的场景。
   * */
  fetchOptions: () => Promise<any>;
}

export interface ArkFormExpose {
  /** 对整个表单的内容进行验证 */
  validate: () => Promise<any>;
  /** 重置表单项为初始值，并移除验证结果 */
  reset: () => void;

  /**
   * 触发可选项重新获取，当交互类型需要选项时可用（例如下拉选择、复选框、单选框）
   *
   * 适用于主动触发选项获取的场景。
   * */
  fetchOptions: (
      formItem: FormItem,
      formItems: FormItem[],
  ) => Promise<any>;
}
